package com.csun.cmny.provider.service.impl;

import com.csun.cmny.base.dto.LoginAuthDto;
import com.csun.cmny.base.enums.ErrorCodeEnum;
import com.csun.cmny.core.support.BaseService;
import com.csun.cmny.provider.constant.Constant;
import com.csun.cmny.provider.dao.OmcOldmanExpenseItemMapper;
import com.csun.cmny.provider.exceptions.OmcBizException;
import com.csun.cmny.provider.model.constant.OldInConstant;
import com.csun.cmny.provider.model.constant.OldmanTypeConstant;
import com.csun.cmny.provider.model.domain.*;
import com.csun.cmny.provider.model.dto.SelectExpenseDto;
import com.csun.cmny.provider.model.dto.SendMessageRequest;
import com.csun.cmny.provider.model.dto.check_in.CheckInDaysDto;
import com.csun.cmny.provider.model.dto.expenseItem.ExpenseItemSelectDto;
import com.csun.cmny.provider.model.vo.*;
import com.csun.cmny.provider.model.vo.check_in.CheckInDaysVo;
import com.csun.cmny.provider.model.vo.expenItem.ExpenseItemTheVo;
import com.csun.cmny.provider.pojo.Bed;
import com.csun.cmny.provider.pojo.Oldman;
import com.csun.cmny.provider.pojo.OldmanLeave;
import com.csun.cmny.provider.pojo.Room;
import com.csun.cmny.provider.service.*;
import com.csun.cmny.provider.utils.DateUtil;
import com.csun.cmny.util.PublicUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class OmcOldmanExpenseItemServiceImpl extends BaseService<OmcOldmanExpenseItem> implements OmcOldmanExpenseItemService {

    @Resource
    private OmcOldmanExpenseItemMapper omcOldmanExpenseItemMapper;
    @Resource
    private OmcExpenseItemService omcExpenseItemService;
    @Resource
    private OmcSetMealService omcSetMealService;
    @Resource
    private OmcPrepaidCycleService omcPrepaidCycleService;
    @Resource
    private OmcReturnFeeConfigService omcReturnFeeConfigService;
    @Resource
    private BedService bedService;
    @Resource
    private RoomService roomService;
    @Resource
    private OmcOldmanPaidExpenseItemService omcOldmanPaidExpenseItemService;
    @Resource
    private OmcOldManBillService omcOldManBillService;
    @Resource
    private OmcOldManSupplementService omcOldManSupplementService;
    @Resource
    private OmcAdvisoryService omcAdvisoryService;
    @Resource
    private OmcSetMealItemService omcSetMealItemService;
    @Resource
    private OldmanService oldmanService;
    @Resource
    private OmcCycleExpenseItemService omcCycleExpenseItemService;
    @Resource
    private OmcExpenseTypeService omcExpenseTypeService;
    @Resource
    private OmcBillMealService omcBillMealService;
    @Resource
    private OmcBillSetMealItemService omcBillSetMealItemService;
    @Resource
    private OmcExpenseTypeModelCodeService omcExpenseTypeModelCodeService;
    @Resource
    private OmcPaymentCycleService omcPaymentCycleService;
    @Resource
    private OmcOldManAccountFundsService omcOldManAccountFundsService;
    @Resource
    private OmcUserTypeService omcUserTypeService;
    @Resource
    private OldmanLeaveService oldmanLeaveService;
    @Resource
    private OpcMessageService opcMessageService;
    @Resource
    private OldmanRechargeService oldmanRechargeService;
    @Resource
    private OldmanNurseHiService oldmanNurseHiService;

    @Override
    public List<ExpenseTypeVo> queryExpenseItem(Integer modelCode, LoginAuthDto loginAuthDto) {
        List<ExpenseTypeVo> expenseTypeVoList = omcOldmanExpenseItemMapper.queryExpenseItem(modelCode,loginAuthDto.getGroupId());

        if(expenseTypeVoList != null && expenseTypeVoList.size() > 0){
            for(ExpenseTypeVo vo : expenseTypeVoList){
                ExpenseItemSelectDto query = new ExpenseItemSelectDto();
                query.setExpenseTypeId(vo.getId());
                List<ExpenseItemTheVo> expenseItemList = omcExpenseItemService.selectExpenItem(query);
                vo.setExpenseItemList(expenseItemList);
            }
        }
        return expenseTypeVoList;
    }

    @Override
    public Integer bindExpenseItem(List<OmcOldmanExpenseItem> oldmanExpenseItemList, LoginAuthDto loginAuthDto) {

        //校验消费类别是否配置完整
        checkExpenseTypeModelCodeComplete(loginAuthDto);
        
        if(oldmanExpenseItemList != null && oldmanExpenseItemList.size() > 0){
            OmcOldmanExpenseItem oldmanExpenseItem = oldmanExpenseItemList.get(0);

            Long oldmanId = oldmanExpenseItem.getOldmanId();

            Oldman oldman = new Oldman();
            oldman.setOldmanId(oldmanId.intValue());
            oldman = oldmanService.selectByOld(oldman);

            if(oldman.getStatus().equals(Constant.DAIPINGGU)){
                throw new OmcBizException(ErrorCodeEnum.OMC10037055);
            }

            //校验入院缴费单支付状态
            checkBillStatus(oldmanId);

            //添加前判断是否修改了消费消费项目
            OmcOldmanExpenseItem deleteItem = new OmcOldmanExpenseItem();
            deleteItem.setOldmanId(oldmanExpenseItem.getOldmanId());
            deleteItem.setModelCode(oldmanExpenseItem.getModelCode());

            //对比是否修改项目
            List<OmcOldmanExpenseItem> itemList = select(deleteItem);
            if(oldmanExpenseItemList.size() == itemList.size()){
                int count = 0;
                for(OmcOldmanExpenseItem newItem : oldmanExpenseItemList){
                    for(OmcOldmanExpenseItem originalItem : itemList){
                        if(newItem.getChargeStandard() != null && originalItem.getChargeStandard() != null){
                            if(newItem.getExpenseItemId().equals(originalItem.getExpenseItemId()) && newItem.getChargeStandard().compareTo(originalItem.getChargeStandard()) == 0){
                                if(newItem.getAmount().equals(originalItem.getAmount())) {
                                    count++;
                                }
                            }
                        }else if(newItem.getChargeStandard() == null && originalItem.getChargeStandard() == null){
                            if(newItem.getExpenseItemId().equals(originalItem.getExpenseItemId())){
                                if(newItem.getAmount().equals(originalItem.getAmount())){
                                    count++;
                                }
                            }
                        }
                    }
                }
                //如果未修改，不操作数据库
                if(count == oldmanExpenseItemList.size()){
                    return 1;
                }
            }

            //如果修改，删除原项目
            int retDelete = delete(deleteItem);

            //此时修改了选择的项目，人工减免录入界面需要重新录入
            int changeRet = changeStatusByOldmanId(oldmanId,0);

            //重新批量添加
            int ret = batchSave(oldmanExpenseItemList);
            return ret;
        }else{
            return 0;
        }

    }

    @Override
    public List<SetMealVo> matchSetMeal(Long oldmanId, LoginAuthDto loginAuthDto) {

        //定义已选择的消费项目Id
        List<Long> selectedItemIdList = new LinkedList<>();

        //查询老人已选择的消费项目
        OmcOldmanExpenseItem oldmanExpenseItemQuery = new OmcOldmanExpenseItem();
        oldmanExpenseItemQuery.setOldmanId(oldmanId);
        List<OmcOldmanExpenseItem> oldmanExpenseItemList = select(oldmanExpenseItemQuery);
        if(oldmanExpenseItemList == null || oldmanExpenseItemList.size() <1){
            throw new OmcBizException(ErrorCodeEnum.OMC10037015);
        }else{
            //将消费项目id放入List
            for(OmcOldmanExpenseItem item : oldmanExpenseItemList){
                selectedItemIdList.add(item.getExpenseItemId());
            }
        }

        //定义查询结果集
        List<SetMealVo> setMealVoList = new LinkedList<>();
        //遍历机构所有的套餐
        OmcSetMeal setMealQuery = new OmcSetMeal();
        setMealQuery.setStatus(1);
        setMealQuery.setGroupId(loginAuthDto.getGroupId());
        List<OmcSetMeal> setMealList = omcSetMealService.queryAll(setMealQuery);

        if(setMealList != null && setMealList.size() >0){
            //遍历套餐中的消费项目id
            for(OmcSetMeal item : setMealList){
                List<Long> setMealItemIdList = new LinkedList<>();
                List<OmcSetMealItem> setMealItemList = item.getSetMealItemList();
                if(setMealItemList != null || setMealItemIdList.size() > 0){
                   //将套餐中的消费项目id存入List
                   for(OmcSetMealItem setMealItem : setMealItemList){
                        setMealItemIdList.add(setMealItem.getExpenseItemId());
                    }
                }
                //如果老人选择的项目包含套餐的项目，将该套餐加入返回结果集
                if(selectedItemIdList.containsAll(setMealItemIdList)){
                    //创建套餐vo对象
                    SetMealVo setMealVo = new SetMealVo();
                    List<SetMealItemVo> result = new LinkedList<>();
                    //拷贝套餐属性
                    BeanUtils.copyProperties(item,setMealVo);
                    //放入套餐项目
                    List<SetMealItemVo> voList = omcSetMealItemService.queryBySetMealId(setMealVo.getId());
                    setMealVo.setSetMealItemVoList(voList);
                    //将套餐加入结果集
                    setMealVoList.add(setMealVo);
                }
            }
        }
        return setMealVoList;
    }

    @Override
    public List<ExpenseItemVo> queryOldmanExpenseItem(Long oldmanId, LoginAuthDto loginAuthDto) {

        //定义已选择的消费项目Id集合
        List<Long> selectedItemIdList = new LinkedList<>();

        //查询老人已选择的消费项目
        OmcOldmanExpenseItem oldmanExpenseItemQuery = new OmcOldmanExpenseItem();
        oldmanExpenseItemQuery.setOldmanId(oldmanId);
        List<OmcOldmanExpenseItem> oldmanExpenseItemList = select(oldmanExpenseItemQuery);
        if(oldmanExpenseItemList == null || oldmanExpenseItemList.size() <1){
            throw new OmcBizException(ErrorCodeEnum.OMC10037015);
        }else{
            //将消费项目id放入List
            for(OmcOldmanExpenseItem item : oldmanExpenseItemList){
                selectedItemIdList.add(item.getExpenseItemId());
            }
            //按消费项目Id查询老人选择的消费项目的详细信息（包括减免比例）
            List<ExpenseItemVo> expenseItemVoList = omcOldmanExpenseItemMapper.queryOldmanExpenseItem(oldmanId,selectedItemIdList);

            /*
            * 未配置减免比例时，无法使用queryOldmanExpenseItem()方法查到消费项目
            * 如果未配置人员减免比例，按不减免计算
            * 将未查到的消费项目id通过queryOldmanExpenseItemWithoutSubPersent()方法查询，并将两个结果集合并返回
            * */
            if(expenseItemVoList.size() < oldmanExpenseItemList.size()){

                //移除已经查询到的消费项目id
                int maxSize = selectedItemIdList.size();
                for (int i = maxSize-1; i >=0; i--) {
                    int size = expenseItemVoList.size();
                    while (size > 0) {
                        if (expenseItemVoList.get(size-1).getId().equals(selectedItemIdList.get(i))) {
                            selectedItemIdList.remove(i);
                            break;
                        }
                        size--;
                    }
                }
                //查询剩余消费项目
                List<ExpenseItemVo> surplusVoList = omcOldmanExpenseItemMapper.queryOldmanExpenseItemWithoutSubPersent(selectedItemIdList);
                for(ExpenseItemVo vo : surplusVoList){
                    vo.setPrecent(0);
                    expenseItemVoList.add(vo);
                }
                //判断老人是否选择了消费项目
                if(expenseItemVoList.size() != oldmanExpenseItemList.size()){
                    throw new OmcBizException(ErrorCodeEnum.OMC10037015);
                }
            }

            //先查询原来老人购买时的价格
            OmcOldmanPaidExpenseItem originalItemQuery = new OmcOldmanPaidExpenseItem();
            originalItemQuery.setOldmanId(oldmanId);
            List<OmcOldmanPaidExpenseItem> originalItemList = omcOldmanPaidExpenseItemService.select(originalItemQuery);

            //如果选择的项目有重复的，按原来选择该项目时的价格计算
            if(originalItemList.size() > 0){
                for(ExpenseItemVo vo : expenseItemVoList){
                    for(OmcOldmanPaidExpenseItem item : originalItemList){
                        if(vo.getId().equals(item.getExpenseItemId())){
                            vo.setChargeStandard(item.getItemFee());
                        }
                    }
                }
            }

            //计算减免金额
            for(ExpenseItemVo vo : expenseItemVoList){

                for(OmcOldmanExpenseItem item : oldmanExpenseItemList){
                    if(vo.getId().equals(item.getExpenseItemId())){

                        //获取非固定金额（前端保存的数据）
                        if(vo.getIsFixedPrice() == 0){
                            if(item.getChargeStandard() == null){
                                throw new OmcBizException(ErrorCodeEnum.OMC10037041);
                            }else{
                                BigDecimal fixedChargeStandard = item.getChargeStandard();
                                BigDecimal fixedUserTypeRateRefief = fixedChargeStandard.multiply(new BigDecimal (vo.getPrecent())).divide(new BigDecimal(100));
                                vo.setChargeStandard(item.getChargeStandard());
                                vo.setUserTypeRateRefief(fixedUserTypeRateRefief);
                            }
                        //获取固定金额
                        }else{
                            BigDecimal unFixedChargeStandard = vo.getChargeStandard();
                            BigDecimal unFixedUserTypeRateRefief = unFixedChargeStandard.multiply(new BigDecimal (vo.getPrecent())).divide(new BigDecimal(100));
                            vo.setUserTypeRateRefief(unFixedUserTypeRateRefief);
                        }
                        //放入购买件数
                        vo.setAmount(item.getAmount());
                        vo.setStatus(item.getStatus());
                    }
                }
            }
            return expenseItemVoList;
        }
    }

    @Override
    public Integer generateOldmaInBill(SelectExpenseDto selectExpenseDto, LoginAuthDto loginAuthDto) {

        //获取老人id
        Long oldmanId = selectExpenseDto.getOldmanId();

        //校验缴费单生成日期是否配置
        checkPaymentCycleConfigExsit(loginAuthDto);

        //校验入院缴费单支付状态
        checkBillStatus(oldmanId);

        //获取前端传来的项目信息
        List<OmcOldmanPaidExpenseItem> oldmanPaidExpenseItemList = selectExpenseDto.getOldmanPaidExpenseItemList();

        //获取老人之前选择项目
        List<ExpenseItemVo> expenseItemVoList = queryOldmanExpenseItem(oldmanId,loginAuthDto);


        //校验接收数据是否跟老人选择项目数量相等
        if(oldmanPaidExpenseItemList.size() < 1 || expenseItemVoList.size() != selectExpenseDto.getOldmanPaidExpenseItemList().size()){
            throw new OmcBizException(ErrorCodeEnum.OMC10037016);
        }

        /*
         * 获取老人选择的项目（包含实际费用） oldmanPaidExpenseItemList
         * 获取到的购买项目信息需要写入三张表
         *   1.cn_omc_oldman_paid_expense_item  将所有消费项目写入该表 用于做数据回显
         *   2.cn_omc_oldman_cycle_expense_item 将周期项目写入周期表中 用于生成周期缴费单 调房调级时（仅调整
         * 周期缴费项目），操作该表的数据，不会对入院流程中选择的消费项目产生影响
         *   3.cn_omc_oldman_bill 将入院产生的消费项目写入缴费单表，及缴费单关联的项目表、套餐表、明细表，用于生成
         * 入院缴费单
         *   4.最后将余额存入cn_omc_old_man_account_funds表中
         * */

        //周期预缴费用
        BigDecimal cycleTotalFee = BigDecimal.ZERO;

        //非周期预缴费用
        BigDecimal unCycleTotalFee = BigDecimal.ZERO;

        //入院实际费用
        BigDecimal inActualFee = BigDecimal.ZERO;

        //周期缴费项目集合
        List<OmcCycleExpenseItem> cycleItemList = new LinkedList<>();

        //根据预缴周期id获取预缴配置
        OmcPrepaidCycle omcPrepaidCycle = omcPrepaidCycleService.selectByKey(selectExpenseDto.getPrepaidCycleId());

        //计算预缴周期月数
        BigDecimal prepaidCycleNum = new BigDecimal(omcPrepaidCycle.getPrepaidMonthNum());

        //获取是否需要预缴该月剩余天数
        int isAddSurplusDays = omcPrepaidCycle.getIsAddSurplusDays();

        //计算剩余天数是多少个周期
        CheckInDaysDto checkInDaysDto = new CheckInDaysDto();
        checkInDaysDto.setGroupId(loginAuthDto.getGroupId());
        checkInDaysDto.setCheckInDate(DateUtil.getDateByString(selectExpenseDto.getOldManInDate()));
        CheckInDaysVo checkInDaysVo = omcReturnFeeConfigService.queryCheckInDaysVo(checkInDaysDto);

        //当月剩余周期数
        BigDecimal prepaidSurplus = checkInDaysVo.getPayPercent();

        //当月剩余周期数费用
        BigDecimal surplusCycleFee = BigDecimal.ZERO;

        //实际预缴周期数
        BigDecimal actualPrepaidCycleNum;

        //用户是否选择预缴本月剩余周期
        if(isAddSurplusDays == 1){
            actualPrepaidCycleNum = prepaidSurplus.add(prepaidCycleNum);
        }else{
            actualPrepaidCycleNum = prepaidCycleNum;
        }

        log.info("预缴周期数 : [" + actualPrepaidCycleNum + "]" + "当月剩余周期数 : [" + prepaidSurplus + "]");

        //循环拷贝数据
        for (ExpenseItemVo vo : expenseItemVoList) {
            for(OmcOldmanPaidExpenseItem omc : oldmanPaidExpenseItemList){
                if(vo.getId().equals(omc.getExpenseItemId())){

                    //计算项目实际价格
                    BigDecimal actualFee = vo.getChargeStandard().subtract(vo.getUserTypeRateRefief().add(omc.getUserRateRefief()));

                    //校验前段后台计算数据是否一致
                    if(actualFee.compareTo(omc.getActualFee()) != 0) {
                        throw new OmcBizException(ErrorCodeEnum.OMC10037020);
                    }
                    //拷贝数据
                    omc.setCode(vo.getCode());
                    omc.setExpenseTypeId(vo.getExpenseTypeId().longValue());
                    omc.setExpenseItemId(vo.getId());
                    omc.setActualFee(actualFee);
                    omc.setAmount(vo.getAmount());
                    omc.setOldmanId(oldmanId);
                    omc.setCostType(vo.getCostType());
                    omc.setGroupId(loginAuthDto.getGroupId());
                    omc.setItemFee(vo.getChargeStandard());
                    omc.setItemName(vo.getItemName());
                    omc.setItemType(vo.getExpenseTypeName());
                    omc.setUserTypeRateRefief(vo.getUserTypeRateRefief());
                    omc.setModelCode(vo.getModelCode());
                    omc.setUpdateInfo(loginAuthDto);
                    omc.setIsAdjust(vo.getIsAdjust());
                    omc.setIsLeaveReturn(vo.getIsLeaveReturn());
                    omc.setIsOutReturn(vo.getIsOutReturn());
                    omc.setIsFixedPrice(vo.getIsFixedPrice());

                    log.info("消费项目 :" + omc.getItemName() + "[ 原价 " + vo.getChargeStandard() + "人员类别减免 " + vo.getUserTypeRateRefief() + "人工减免 " + vo.getUserRateRefief() + " 实际费用 " + actualFee + "]");

                    //周期缴费项目  加入周期总费用
                    if(vo.getModelCode().equals(2)){
                        cycleTotalFee = cycleTotalFee.add(actualFee);
                        surplusCycleFee = surplusCycleFee.add(actualFee);
                        omc.setUsedDegree(prepaidSurplus);
                        omc.setResidueDegree(actualPrepaidCycleNum.subtract(prepaidSurplus));

                        //周期项目写入周期项目表
                        OmcCycleExpenseItem item = new OmcCycleExpenseItem();
                        item.setExpenseTypeId(vo.getExpenseTypeId().longValue());
                        BeanUtils.copyProperties(omc,item);
                        item.setCode(vo.getCode());
                        cycleItemList.add(item);
                    }
                    //将入院缴费项目累加
                    if(vo.getModelCode().equals(1)){
                        inActualFee = inActualFee.add(actualFee.multiply(new BigDecimal(vo.getAmount())));
                        omc.setUsedDegree(BigDecimal.ZERO);
                        omc.setResidueDegree(BigDecimal.ONE);
                    }
                    //将非周期缴费项目累加
                    if(vo.getModelCode().equals(4)){
                        BigDecimal amount = new BigDecimal(vo.getAmount());
                        unCycleTotalFee = unCycleTotalFee.add(actualFee.multiply(amount));
//                        accountSurplusFee = accountSurplusFee.add(actualFee.multiply(amount));
                        omc.setUsedDegree(BigDecimal.ZERO);
                        omc.setResidueDegree(amount);
                    }
                }
            }
        }

        //[周期费用乘以预缴周期数] 预缴费用
        cycleTotalFee = actualPrepaidCycleNum.multiply(cycleTotalFee).setScale(2,BigDecimal.ROUND_HALF_UP);

        //创建存入缴费单的套餐对象
        OmcBillMeal omcBillMeal = new OmcBillMeal();

        //创建存入缴费单的套餐项目集合
        List<OmcBillSetMealItem> billSetMealItemList = new LinkedList<>();

        //匹配套餐
        if(selectExpenseDto.getSetMealId() != null && selectExpenseDto.getSetMealId() != 0){

            //查询套餐
            SetMealVo setMealVo = omcSetMealService.getById(selectExpenseDto.getSetMealId());

            log.info("套餐名称 " + setMealVo.getName() + "[ 原价 : " + setMealVo.getOriginalPrice() + " 实际价格 : " + setMealVo.getActualPrice() + " ]");

            //获取套餐项目
            List<SetMealItemVo> setMealItemVoList = setMealVo.getSetMealItemVoList();
            if(setMealItemVoList != null && setMealItemVoList.size() > 0){
                for(SetMealItemVo vo : setMealItemVoList){

                    //将套餐中项目的次数存入老人购买的周期服务
                    for(OmcCycleExpenseItem omc : cycleItemList){
                        if(vo.getExpenseItemId().equals(omc.getExpenseItemId())){
                            omc.setResidueDegree(new BigDecimal(vo.getTimes()).subtract(prepaidSurplus));
                        }
                    }
                    //将套餐中包含的项目的费用从之前的计费中减去
                    for(OmcOldmanPaidExpenseItem omc : oldmanPaidExpenseItemList){
                        if(vo.getExpenseItemId().equals(omc.getExpenseItemId())){

                            //将套餐数据处理后存入缴费单套餐项目表
                            OmcBillSetMealItem item = new OmcBillSetMealItem();
                            BeanUtils.copyProperties(vo,item);

                            //预缴费用减去套餐中的项目费用
                            if (omc.getModelCode().equals(1)) {
                                inActualFee = inActualFee.subtract(omc.getActualFee().multiply(new BigDecimal(vo.getTimes())));
                                item.setUsedDegree(BigDecimal.ZERO);
                                item.setResidueDegree(new BigDecimal(vo.getTimes()));
                            }
                            if (omc.getModelCode().equals(2)) {
                                //预缴周期不能小于套餐中项目的周期数
                                if(actualPrepaidCycleNum.compareTo(new BigDecimal(vo.getTimes())) < 0 ){
                                    throw new OmcBizException(ErrorCodeEnum.OMC10037021);
                                }
                                BigDecimal itemFee = omc.getActualFee().multiply(new BigDecimal(vo.getTimes()));
                                cycleTotalFee = cycleTotalFee.subtract(itemFee);
                                surplusCycleFee = surplusCycleFee.subtract(omc.getActualFee());
                                item.setUsedDegree(prepaidSurplus);
                                item.setResidueDegree(new BigDecimal(vo.getTimes()).subtract(prepaidSurplus));
                            }
                            if (omc.getModelCode().equals(4)) {
                                BigDecimal itemFee = omc.getActualFee().multiply(new BigDecimal(vo.getTimes()));
                                unCycleTotalFee = unCycleTotalFee.subtract(itemFee);
                                item.setUsedDegree(BigDecimal.ZERO);
                                item.setResidueDegree(new BigDecimal(vo.getTimes()));
                            }
                            item.setExpenseItemName(vo.getItemName());
                            item.setExpenseTypeId(vo.getExpenseTypeId().longValue());
                            item.setModelCode(omc.getModelCode());
                            item.setContent(vo.getContent());
                            item.setCostType(vo.getCostType());
                            item.setIsAdjust(omc.getIsAdjust());
                            item.setIsLeaveReturn(omc.getIsLeaveReturn());
                            item.setIsOutReturn(omc.getIsOutReturn());
                            item.setId(null);
                            billSetMealItemList.add(item);

                            log.info("套餐项目 :" + item.getExpenseItemName() + "[ 使用次数 " + item.getUsedDegree() + "剩余次数 " + item.getResidueDegree() + "]");
                        }
                    }
                }
            }
            //如果购买了套餐
            if(setMealVo != null){

                //入院实缴费用加上套餐费用
                inActualFee = inActualFee.add(setMealVo.getActualPrice());

                //将套餐信息存储在入院缴费单的套餐表中
                omcBillMeal.setSetMealId(setMealVo.getId());
                omcBillMeal.setOriginFee(setMealVo.getOriginalPrice());
                omcBillMeal.setActualFee(setMealVo.getActualPrice());
                omcBillMeal.setMealName(setMealVo.getName());
                omcBillMeal.setReducedPrice(setMealVo.getSubPrice());
                omcBillMeal.setRemark(setMealVo.getRemark());
            }
        }

        //预缴费用 = 周期预缴 + 费周期预缴
        BigDecimal totalPrepaidFee = cycleTotalFee.add(unCycleTotalFee);

        //入院缴费 = 入院项目费用 + 预缴费用
        inActualFee = inActualFee.add(totalPrepaidFee).setScale(2,BigDecimal.ROUND_HALF_UP);

        log.info("预缴费用 [ 后端计算结果 : " + totalPrepaidFee + " 前端计算结果 : " + selectExpenseDto.getPrepaidFee() + "]" );
        log.info("入院缴费 [ 后端计算结果 : " + inActualFee + " 前端计算结果 : " + selectExpenseDto.getTotalFee() + "]" );
        log.info("预缴周期数 : [" + actualPrepaidCycleNum + "]" + " 本月剩余周期数 : [" + prepaidSurplus + "]");

        //校验前后端费用计算是否一致
        if(totalPrepaidFee.compareTo(selectExpenseDto.getPrepaidFee())!=0){
            throw new OmcBizException(ErrorCodeEnum.OMC10037032);
        }
        if(inActualFee.compareTo(selectExpenseDto.getTotalFee())!=0){
            throw new OmcBizException(ErrorCodeEnum.OMC10037033);
        }

        //保存周期缴费项目 保存之前将原有数据删除
        int retCycle = omcCycleExpenseItemService.batchSaveCycleExpenseItem(cycleItemList);

        //保存缴费项目明细 保存之前将原有数据删除
        int retIn = omcOldmanPaidExpenseItemService.batchSaveOldmanPaidExpenseItem(oldmanPaidExpenseItemList);

        //将之前选择的项目是否需要支付状态改为1,该状态码为1时，人工减免页面做回显
        int retChange = changeStatusByOldmanId(oldmanId,1);

        //生成入院账单
        //1.生成缴费单基本信息
        OmcOldManBill oldManBill = new OmcOldManBill();
        oldManBill.setOldManId(oldmanId);
        oldManBill.setTotalPay(inActualFee);
        oldManBill.setInDate(selectExpenseDto.getOldManInDate());


        OmcOldManSupplement oldManSupplement = new OmcOldManSupplement();
        oldManSupplement.setOldManId(oldmanId);
        oldManSupplement = omcOldManSupplementService.selectOne(oldManSupplement);
        OmcUserType omcUserType = omcUserTypeService.selectByKey(oldManSupplement.getPeopleType());




        if (PublicUtil.isNotEmpty(oldManSupplement.getBedId())){
            Bed bed = bedService.selectById(oldManSupplement.getBedId().intValue());
            if (PublicUtil.isNotEmpty(bed)){
                Room room = roomService.selectById(bed.getRoomId());
                oldManBill.setBedNo(bed.getBedNo().toString());
                oldManBill.setRoomNo(room.getRoomNo());
            }
        }

        //修改老人状态 改为待缴费
        Oldman oldmanQuery = new Oldman();
        oldmanQuery.setOldmanId(oldmanId.intValue());
        oldmanQuery = oldmanService.selectByOld(oldmanQuery);
        oldmanQuery.setStatus(2);

        //创建推送请求对象 老人缴费单生成
        SendMessageRequest sendMessageRequest = new SendMessageRequest();
        sendMessageRequest.setGroupId(loginAuthDto.getGroupId());

        if (PublicUtil.isNotEmpty(omcUserType)){
            if(omcUserType.getUserTypeCode().equals(OldmanTypeConstant.OHTER_TYPE_PEOPLE)){
                //需要院长审批
                oldManBill.setIsPassed(2);
                //其他人员类别 设置老人状态为待审批
                oldmanQuery.setStatus(12);
                sendMessageRequest.setMsgCode(OldInConstant.IN_FLOW_OTHER_PEOPLE_BILL_GENERATE);
            }else{
                sendMessageRequest.setMsgCode(OldInConstant.IN_FLOW_BILL_GENERATE);
            }
        }

        //发送推送
        opcMessageService.pushWithMsgCode(sendMessageRequest);

        //修改老人信息
        int updateRet = oldmanService.updateByOldId(oldmanQuery);

        //2.生成缴费单项目明细
        List<OmcBillItem> billItemList = new LinkedList<>();
        for(OmcOldmanPaidExpenseItem omc : oldmanPaidExpenseItemList){
            OmcBillItem item = new OmcBillItem();
            BeanUtils.copyProperties(omc,item);
            item.setId(null);
            billItemList.add(item);
        }

        //3.将套餐项目放入缴费单套餐对象
        omcBillMeal.setBillSetMealItemList(billSetMealItemList);

        //4.生成缴费单费用明细
        OmcBillInHospitalFee billInHospitalFee = new OmcBillInHospitalFee();
        billInHospitalFee.setActualFee(selectExpenseDto.getOriginalFee());
        billInHospitalFee.setUserRateRefief(selectExpenseDto.getManualReducefee());
        billInHospitalFee.setUserTypeRateRefief(selectExpenseDto.getPersonCategoryReduceFee());
        billInHospitalFee.setTotalFee(inActualFee);
        billInHospitalFee.setLastMonthFee(totalPrepaidFee);

        //5.生成入院缴费单
        int result = omcOldManBillService.saveInHospitalBill(oldManBill,billItemList,omcBillMeal,billInHospitalFee,loginAuthDto);

        //6.改变床位状态
        //查询选择的床位Id

        if(oldManSupplement != null){

            //校验床位状态
            //如果之前该老人生成缴费单绑定了床位号，先把原来的绑定取消
            Bed bedQuery = new Bed();
            bedQuery.setOldmanId(oldmanId.intValue());
            bedQuery = bedService.selectByBed(bedQuery);
            if(bedQuery != null){
                bedQuery.setOldmanId(null);
                bedQuery.setStatus(0);
                int bedUpdate = bedService.updateBedOldmanIdAndStatus(bedQuery);
            }

            Long bedId = oldManSupplement.getBedId();
            if(bedId == null){
                throw new OmcBizException(ErrorCodeEnum.OMC10037038);
            }

            Bed bedCheck = bedService.selectById(bedId.intValue());

            //校验床位状态
            if(bedCheck.getStatus().equals(0) || bedCheck.getStatus().equals(3)){
                //如果床位状态为咨询预约，查询是否是同一人
                if(bedCheck.getStatus().equals(3)){

                    //设置咨询记录id
                    Long bedAdvisoryId = null;
                    OmcOldManSupplement osQuery = new OmcOldManSupplement();
                    osQuery.setOldManId(oldmanId);
                    osQuery = omcOldManSupplementService.selectOne(osQuery);
                    if(osQuery.getAdvisoryId() != null){
                        OmcAdvisory advisoryQuery = omcAdvisoryService.selectByKey(osQuery.getAdvisoryId());
                        if(advisoryQuery != null && advisoryQuery.getBedId() != null){
                            Bed bedAdvisory = bedService.selectById(advisoryQuery.getBedId().intValue());
                            if(bedAdvisory.getBedId() != null){
                                bedAdvisoryId = bedAdvisory.getBedId().longValue();
                            }
                        }
                    }
                    if(bedAdvisoryId == null || !bedAdvisoryId.equals(bedId)){
                        throw new OmcBizException(ErrorCodeEnum.OMC10034009);
                    }
                }
            }else {
                throw new OmcBizException(ErrorCodeEnum.OMC10034006);
            }

            //(1)修改床位状态 床位状态 0-空床 1-暂出 2-有人  3-咨询入住时的预约 4-入住时的预约 5 - 试入住 6-调房预约 7-待缴费
            bedCheck.setStatus(7);
            bedCheck.setOldmanId(oldmanId.intValue());
            int bedRet = bedService.updateById(bedCheck);

            //(2)存入老人入院日期、预缴周期id
            oldManSupplement.setInDate(selectExpenseDto.getOldManInDate());
            oldManSupplement.setPrepaidCycleId(selectExpenseDto.getPrepaidCycleId());
            oldManSupplement.setUpdateInfo(loginAuthDto);
            int dateRet = omcOldManSupplementService.update(oldManSupplement);

        }else{
            throw new OmcBizException(ErrorCodeEnum.OMC10038002);
        }

        //7.将余额存入cn_omc_old_man_account_funds表中
        OmcOldManAccountFunds oaf = new OmcOldManAccountFunds();
        oaf.setOldManId(oldmanId);
        oaf = omcOldManAccountFundsService.selectOne(oaf);
        //修改余额
        oaf.setActPaidFee(inActualFee);
        oaf.setRemainder(totalPrepaidFee.subtract(surplusCycleFee.multiply(prepaidSurplus)));
        int updateAccountFunds = omcOldManAccountFundsService.update(oaf);

        //log.info("老人 : " + oldmanQuery.getOldName() + " [ 入院日期 : " + selectExpenseDto.getOldManInDate() + "人员类别 : " + omcUserType.getUserTypeName() + "床位 : " + oldManSupplement.getBedId() + " ]");

        return result;
    }

    @Override
    public OmcExpenseItem mathcBedFeeByBedId(Long bedId, LoginAuthDto loginAuthDto) {

        //根据id查询床位信息
        Bed bed = bedService.selectById(bedId.intValue());
        //根据床位查询房间信息
        Room room = roomService.selectById(bed.getRoomId());

        //查询床位的收费标准
        OmcExpenseItem expenseItemQuery = new OmcExpenseItem();

        //关闭朝向的匹配
//        expenseItemQuery.setRoomDirection(room.getRoomDirection());

        expenseItemQuery.setHasToilet(room.getHasToilet());
        expenseItemQuery.setRoomType(room.getRoomType());
        expenseItemQuery.setGroupId(loginAuthDto.getGroupId());

        expenseItemQuery = omcExpenseItemService.selectOne(expenseItemQuery);

        if(expenseItemQuery == null){
            throw new OmcBizException(ErrorCodeEnum.OMC10037017);
        }

        return expenseItemQuery;
    }

    @Override
    public OmcExpenseItem mathcCareFeeByCareType(Long levelCareId, LoginAuthDto loginAuthDto) {

        //查询护理费用
        OmcExpenseItem expenseItemQuery = new OmcExpenseItem();
        expenseItemQuery.setLevelCareId(levelCareId);
        expenseItemQuery.setGroupId(loginAuthDto.getGroupId());
        List<OmcExpenseItem> expenseItemQuerys = omcExpenseItemService.select(expenseItemQuery);

        if(PublicUtil.isEmpty(expenseItemQuerys)){
            throw new OmcBizException(ErrorCodeEnum.OMC10037018);
        }
        return expenseItemQuerys.get(0);
    }

    @Override
    public Long getAdvisoryBedId(Long oldmanId, LoginAuthDto loginAuthDto) {

        //查询老人额外信息表
        OmcOldManSupplement oldManSupplementQuery = new OmcOldManSupplement();
        oldManSupplementQuery.setOldManId(oldmanId);
        oldManSupplementQuery = omcOldManSupplementService.selectOne(oldManSupplementQuery);

        //查询是否有咨询记录
        if(oldManSupplementQuery != null && oldManSupplementQuery.getAdvisoryId() != null){

            //返回咨询记录上的床位id
            OmcAdvisory advisory = omcAdvisoryService.selectByKey(oldManSupplementQuery.getAdvisoryId());
            if (PublicUtil.isNotEmpty(advisory.getBedId())){
                return advisory.getBedId().longValue();
            }
        }
        return null;
    }

    @Override
    public Integer setSelectBedId(Long oldmanId, Long bedId, LoginAuthDto loginAuthDto) {

        //校验入院缴费单支付状态
        checkBillStatus(oldmanId);

        //校验床位状态  放在缴费单生成时校验
//        checkBedStatus(bedId,oldmanId);

        //校验床位护理等级是否配置
        Bed bed = bedService.selectById(bedId.intValue());
        if(bed.getLevelCareId() == null){
            throw new OmcBizException(ErrorCodeEnum.OMC10034008);
        }

        //暂存老人床位Id
        OmcOldManSupplement oldManSupplementQuery = new OmcOldManSupplement();
        oldManSupplementQuery.setOldManId(oldmanId);
        oldManSupplementQuery = omcOldManSupplementService.selectOne(oldManSupplementQuery);
        if(oldManSupplementQuery != null){

            //如果咨询记录预约的床位跟选择的床位不同，取消咨询记录的预约
            if(oldManSupplementQuery.getAdvisoryId() != null){
                OmcAdvisory advisory = omcAdvisoryService.selectByKey(oldManSupplementQuery.getAdvisoryId());
                if(advisory != null && advisory.getBedId() != null){
                    if(!advisory.getBedId().equals(bedId.intValue())){
                        Bed bedAdvisory = bedService.selectById(advisory.getBedId());
                        bedAdvisory.setStatus(0);
                        int ret = bedService.updateById(bedAdvisory);
                    }
                }
            }

            //暂存选择的床位id到老人补充表
            oldManSupplementQuery.setBedId(bedId);
            int ret = omcOldManSupplementService.update(oldManSupplementQuery);
            return ret;
        }else{
            throw new OmcBizException(ErrorCodeEnum.OMC10031017);
        }
    }

    @Override
    public BillOldmanInfoVo getOldmanInfoByOldmanId(Long oldmanId, LoginAuthDto loginAuthDto) {

        BillOldmanInfoVo vo = omcOldmanExpenseItemMapper.getOldmanInfoByOldmanId(oldmanId);

        //查找入院缴费单
        OmcOldManBill billQuery = new OmcOldManBill();
        billQuery.setOldManId(oldmanId);
        billQuery.setBillType(1);
        List<OmcOldManBill> omcOldManBills = omcOldManBillService.select(billQuery);

        /*
        * 2020-07-28
        * xcr
        * 二次入院-选择最新入院账单的信息
        * */
        if(omcOldManBills != null && omcOldManBills.size() > 0){

            billQuery = omcOldManBills.get(0);

            for (OmcOldManBill bill : omcOldManBills) {
                if(bill.getCreatedTime().compareTo(billQuery.getCreatedTime()) > 0){
                    billQuery = bill;
                }
            }
        }
        
        if(billQuery.getId() != null){
            //查找入院购买的套餐
            OmcBillMeal billMealQuery = new OmcBillMeal();
            billMealQuery.setBillId(billQuery.getId());
            billMealQuery = omcBillMealService.selectOne(billMealQuery);
            if(billMealQuery != null){
                OmcBillSetMealItem billSetMealItemQuery = new OmcBillSetMealItem();
                billSetMealItemQuery.setSetmealId(billMealQuery.getSetMealId());
                billSetMealItemQuery.setBillId(billQuery.getId());
                List<OmcBillSetMealItem> billSetMealItemList = omcBillSetMealItemService.select(billSetMealItemQuery);
                billMealQuery.setBillSetMealItemList(billSetMealItemList);
                vo.setSetMeal(billMealQuery);
            }
        }
        return vo;
    }

    @Override
    public Integer deleteSelectItemByModelCode(Long oldmanId, Integer modelCode, LoginAuthDto loginAuthDto) {

        OmcOldmanExpenseItem delete = new OmcOldmanExpenseItem();
        delete.setOldmanId(oldmanId);
        delete.setModelCode(modelCode);
        int ret = omcOldmanExpenseItemMapper.delete(delete);
        int retChangeStatus = changeStatusByOldmanId(oldmanId,0);
        return ret;
    }

    @Override
    public Integer oldmanInOfLeyi(SelectExpenseDto selectExpenseDto, LoginAuthDto loginAuthDto) {
        //获取老人id
        Long oldmanId = selectExpenseDto.getOldmanId();

        //校验入院缴费单支付状态
        checkBillStatus(oldmanId);

        //获取前端传来的项目信息
        List<OmcOldmanPaidExpenseItem> oldmanPaidExpenseItemList = selectExpenseDto.getOldmanPaidExpenseItemList();

        //获取老人之前选择项目
        List<ExpenseItemVo> expenseItemVoList = queryOldmanExpenseItem(oldmanId,loginAuthDto);

        //校验是否有必选项目
//        OmcExpenseType expenseTypeQuery = new OmcExpenseType();
//        expenseTypeQuery.setGroupId(loginAuthDto.getGroupId());
//        List<OmcExpenseType> omcExpenseTypes = omcExpenseTypeService.select(expenseTypeQuery);
//        Set<Integer> collect = omcExpenseTypes.stream().map(e -> e.getNeedSelectOne()).collect(Collectors.toSet());
//        if(collect.contains(1)){
            //校验接收数据是否跟老人选择项目数量相等


            if(oldmanPaidExpenseItemList.size() < 1 || expenseItemVoList.size() != selectExpenseDto.getOldmanPaidExpenseItemList().size()){
                throw new OmcBizException(ErrorCodeEnum.OMC10037016);
            }
//        }

        /*
         * 获取老人选择的项目（包含实际费用） oldmanPaidExpenseItemList
         * 获取到的购买项目信息需要写入两张表
         *   1.cn_omc_oldman_paid_expense_item  将所有消费项目写入该表 用于做数据回显
         *   2.乐颐版入院无周期项目
         *   3.cn_omc_oldman_bill 将入院产生的消费项目写入缴费单表，及缴费单关联的项目表、套餐表、明细表，用于生成
         * 入院缴费单
         *   4.最后将余额存入cn_omc_old_man_account_funds表中
         * */
        //非周期预缴费用
        BigDecimal unCycleTotalFee = new BigDecimal(0.00);

        //入院实际费用
        BigDecimal inActualFee = new BigDecimal(0.00);

        //循环拷贝数据
        for(ExpenseItemVo vo : expenseItemVoList){
            for(OmcOldmanPaidExpenseItem omc : oldmanPaidExpenseItemList){
                if(vo.getId().equals(omc.getExpenseItemId())){
                    //计算项目实际价格
                    BigDecimal actualFee = vo.getChargeStandard().subtract(vo.getUserTypeRateRefief().add(omc.getUserRateRefief()));
                    //校验前段后台计算数据是否一致
//                    if(actualFee.compareTo(omc.getActualFee()) != 0) {
//                        throw new OmcBizException(ErrorCodeEnum.OMC10037020);
//                    }
                    //拷贝数据
                    omc.setCode(vo.getCode());
                    omc.setExpenseTypeId(vo.getExpenseTypeId().longValue());
                    omc.setExpenseItemId(vo.getId());
                    omc.setActualFee(actualFee);
                    omc.setAmount(vo.getAmount());
                    omc.setOldmanId(oldmanId);
                    omc.setCostType(vo.getCostType());
                    omc.setGroupId(loginAuthDto.getGroupId());
                    omc.setItemFee(vo.getChargeStandard());
                    omc.setItemName(vo.getItemName());
                    omc.setItemType(vo.getExpenseTypeName());
                    omc.setUserTypeRateRefief(vo.getUserTypeRateRefief());
                    omc.setModelCode(vo.getModelCode());
                    omc.setUpdateInfo(loginAuthDto);
                    omc.setIsAdjust(vo.getIsAdjust());
                    omc.setIsLeaveReturn(vo.getIsLeaveReturn());
                    omc.setIsOutReturn(vo.getIsOutReturn());
                    omc.setIsFixedPrice(vo.getIsFixedPrice());
                    //将入院缴费项目累加
                    if(vo.getModelCode().equals(1)){
                        inActualFee = inActualFee.add(actualFee.multiply(new BigDecimal(vo.getAmount())));
                        omc.setUsedDegree(BigDecimal.ZERO);
                        omc.setResidueDegree(BigDecimal.ONE);
                    }
                    //将非周期缴费项目累加
                    if(vo.getModelCode().equals(4)){
                        BigDecimal amount = new BigDecimal(vo.getAmount());
                        unCycleTotalFee = unCycleTotalFee.add(actualFee.multiply(amount));
                        omc.setUsedDegree(BigDecimal.ZERO);
                        omc.setResidueDegree(amount);
                    }
                }
            }
        }
        //创建存入缴费单的套餐对象
        OmcBillMeal omcBillMeal = new OmcBillMeal();
        //创建存入缴费单的套餐项目集合
        List<OmcBillSetMealItem> billSetMealItemList = new LinkedList<>();
        //匹配套餐
        if(selectExpenseDto.getSetMealId() != null && selectExpenseDto.getSetMealId() != 0){
            //查询套餐
            SetMealVo setMealVo = omcSetMealService.getById(selectExpenseDto.getSetMealId());
            //获取套餐项目
            List<SetMealItemVo> setMealItemVoList = setMealVo.getSetMealItemVoList();
            if(setMealItemVoList != null && setMealItemVoList.size() > 0){
                for(SetMealItemVo vo : setMealItemVoList){

                    //将套餐中包含的项目的费用从之前的计费中减去
                    for(OmcOldmanPaidExpenseItem omc : oldmanPaidExpenseItemList){
                        if(vo.getExpenseItemId().equals(omc.getExpenseItemId())){

                            //将套餐数据处理后存入缴费单套餐项目表
                            OmcBillSetMealItem item = new OmcBillSetMealItem();
                            BeanUtils.copyProperties(vo,item);

                            //预缴费用减去套餐中的项目费用
                            if (omc.getModelCode().equals(1)) {
                                inActualFee = inActualFee.subtract(omc.getActualFee().multiply(new BigDecimal(vo.getTimes())));
                                item.setUsedDegree(BigDecimal.ZERO);
                                item.setResidueDegree(new BigDecimal(vo.getTimes()));
                            }
                            if (omc.getModelCode().equals(4)) {
                                BigDecimal itemFee = omc.getActualFee().multiply(new BigDecimal(vo.getTimes()));
                                unCycleTotalFee = unCycleTotalFee.subtract(itemFee);
                                item.setUsedDegree(BigDecimal.ZERO);
                                item.setResidueDegree(new BigDecimal(vo.getTimes()));
                            }
                            item.setExpenseItemName(vo.getItemName());
                            item.setExpenseTypeId(vo.getExpenseTypeId().longValue());
                            item.setModelCode(omc.getModelCode());
                            item.setContent(vo.getContent());
                            item.setCostType(vo.getCostType());
                            item.setIsAdjust(omc.getIsAdjust());
                            item.setIsLeaveReturn(omc.getIsLeaveReturn());
                            item.setIsOutReturn(omc.getIsOutReturn());
                            item.setId(null);
                            billSetMealItemList.add(item);
                        }
                    }
                }
            }
            //如果购买了套餐
            if(setMealVo != null){

                //入院实缴费用加上套餐费用
                inActualFee = inActualFee.add(setMealVo.getActualPrice());

                //将套餐信息存储在入院缴费单的套餐表中
                omcBillMeal.setSetMealId(setMealVo.getId());
                omcBillMeal.setOriginFee(setMealVo.getOriginalPrice());
                omcBillMeal.setActualFee(setMealVo.getActualPrice());
                omcBillMeal.setMealName(setMealVo.getName());
                omcBillMeal.setReducedPrice(setMealVo.getSubPrice());
                omcBillMeal.setRemark(setMealVo.getRemark());
            }
        }

        //总缴费加上预缴费用
        inActualFee = inActualFee.add(unCycleTotalFee);

        //校验前后端费用计算是否一致
        if(unCycleTotalFee.compareTo(selectExpenseDto.getPrepaidFee())!=0){
            throw new OmcBizException(ErrorCodeEnum.OMC10037032);
        }
        if(inActualFee.compareTo(selectExpenseDto.getTotalFee())!=0){
            throw new OmcBizException(ErrorCodeEnum.OMC10037033);
        }

        //保存缴费项目明细 保存之前将原有数据删除
        int retIn = omcOldmanPaidExpenseItemService.batchSaveOldmanPaidExpenseItem(oldmanPaidExpenseItemList);

        //将之前选择的项目是否需要支付状态改为1,该状态码为1时，人工减免页面做回显
        int retChange = changeStatusByOldmanId(oldmanId,1);

        //生成入院账单
        //1.生成缴费单基本信息
        OmcOldManBill oldManBill = new OmcOldManBill();
        oldManBill.setOldManId(oldmanId);
        oldManBill.setTotalPay(inActualFee);
        oldManBill.setIsPassed(1);
        oldManBill.setBillType(1);
        oldManBill.setIsPay(1);
        oldManBill.setInDate(selectExpenseDto.getOldManInDate());

        //2.生成缴费单项目明细
        List<OmcBillItem> billItemList = new LinkedList<>();
        for(OmcOldmanPaidExpenseItem omc : oldmanPaidExpenseItemList){
            OmcBillItem item = new OmcBillItem();
            BeanUtils.copyProperties(omc,item);
            item.setId(null);
            billItemList.add(item);
        }

        //3.将套餐项目放入缴费单套餐对象
        omcBillMeal.setBillSetMealItemList(billSetMealItemList);

        //4.生成缴费单费用明细
        OmcBillInHospitalFee billInHospitalFee = new OmcBillInHospitalFee();
        billInHospitalFee.setActualFee(selectExpenseDto.getOriginalFee());
        billInHospitalFee.setUserRateRefief(selectExpenseDto.getManualReducefee());
        billInHospitalFee.setUserTypeRateRefief(selectExpenseDto.getPersonCategoryReduceFee());
        billInHospitalFee.setTotalFee(inActualFee);
        billInHospitalFee.setLastMonthFee(unCycleTotalFee);

        //5.生成入院缴费单
        int result = omcOldManBillService.saveInHospitalBill(oldManBill,billItemList,omcBillMeal,billInHospitalFee,loginAuthDto);

        //6.改变老人状态和床位状态
        OmcOldManSupplement omcOldManSupplementQuery = new OmcOldManSupplement();
        omcOldManSupplementQuery.setOldManId(oldmanId);
        omcOldManSupplementQuery = omcOldManSupplementService.selectOne(omcOldManSupplementQuery);
        //(1)存入老人入院日期
        omcOldManSupplementQuery.setInDate(selectExpenseDto.getOldManInDate());
        omcOldManSupplementQuery.setUpdateInfo(loginAuthDto);
        omcOldManSupplementQuery.setIsPayed(1);
        int dateRet = omcOldManSupplementService.update(omcOldManSupplementQuery);

        //(2)修改老人入住状态 改为已入院
        //0-未入院 1-待评估 2-待缴费 3-已入院  4-已出院 5-试入住 6-去世 7-请假中 8-调房调级中 9-出院中 10-app用户
        Oldman oldmanQuery = new Oldman();
        oldmanQuery.setOldmanId(oldmanId.intValue());
        oldmanQuery = oldmanService.selectByOld(oldmanQuery);
        if(!oldmanQuery.getStatus().equals(Constant.YIRUYUAN)){
            //清空老人的护理记录
            Map<String,Object> map = new HashMap<>();
            map.put("oldmanId",oldmanId.longValue());
            map.put("groupId",loginAuthDto.getGroupId());
            oldmanNurseHiService.deleteByOldmanId(oldmanId.intValue());
            int qinkong = oldmanNurseHiService.deleteAll(map);

            //删除原来的出院记录
            oldmanLeaveService.deleteByOid(oldmanId.intValue());

            //插入乐怡出院对象
            OldmanLeave oldmanLeave = new OldmanLeave();
            oldmanLeave.setOldmanId(oldmanId.intValue());
            oldmanLeave.setGroupId(loginAuthDto.getGroupId());
            //oldmanLeave.setLeaveDate(new Date());
            //插入出院记录
            oldmanLeaveService.insertSelective(oldmanLeave);

            //清除充值记录
            oldmanRechargeService.deleteByOldmanId(oldmanId.intValue());

            oldmanQuery.setStatus(Constant.YIRUYUAN);
            int updateRet = oldmanService.updateByOldId(oldmanQuery);

            OmcOldManAccountFunds oaf = new OmcOldManAccountFunds();
            oaf.setOldManId(oldmanId);
            oaf = omcOldManAccountFundsService.selectOne(oaf);
            //实际缴费
            oaf.setActPaidFee(inActualFee);
            //预缴金额
            oaf.setDeposited(unCycleTotalFee);
            //清空充值金额
            oaf.setRecharge(BigDecimal.ZERO);
            //清空消费金额
            oaf.setMonetary(BigDecimal.ZERO);
            //账户余额
            oaf.setRemainder(unCycleTotalFee);
            int updateAccountFunds = omcOldManAccountFundsService.update(oaf);
        }

        //校验床位状态
        //如果之前该老人生成缴费单绑定了床位号，先把原来的绑定取消
        Bed bedQuery = new Bed();
        bedQuery.setOldmanId(oldmanId.intValue());
        bedQuery = bedService.selectByBed(bedQuery);
        if(bedQuery != null){
            int bedUpdate = bedService.cleanOldmanById(bedQuery.getBedId());
        }

        //选择了床位时，对床位进行操作
        if(omcOldManSupplementQuery != null && omcOldManSupplementQuery.getBedId() != null && !omcOldManSupplementQuery.getBedId().equals(0)){
            Long bedId = omcOldManSupplementQuery.getBedId();
            if(bedId != null && bedId != 0){
                Bed bedCheck = bedService.selectById(bedId.intValue());
                //(1)修改床位状态 床位状态 0-空床 1-暂出 2-有人  3-咨询入住时的预约 4-入住时的预约 5 - 试入住 6-调房预约 7-待缴费
                bedCheck.setStatus(2);
                bedCheck.setOldmanId(oldmanId.intValue());
                int bedRet = bedService.updateById(bedCheck);
            }
        }

        return result;
    }


    public BigDecimal getPrepaidCycle(SelectExpenseDto selectExpenseDto, LoginAuthDto loginAuthDto){

        //获取预缴周期配置
        OmcPrepaidCycle omcPrepaidCycle = omcPrepaidCycleService.selectByKey(selectExpenseDto.getPrepaidCycleId());

        //获取预缴周期
        int prepaidCycle = omcPrepaidCycle.getPrepaidMonthNum();

        //预缴周期转型为BigDecimal
        BigDecimal prepaidCycleNum = new BigDecimal(prepaidCycle);

        //如果要预缴本月剩余天数
        if(omcPrepaidCycle.getIsAddSurplusDays() == 1){
            //计算本月剩余周期加入预缴周期
            CheckInDaysDto checkInDaysDto = new CheckInDaysDto();
            checkInDaysDto.setGroupId(loginAuthDto.getGroupId());
            checkInDaysDto.setCheckInDate(DateUtil.getDateByString(selectExpenseDto.getOldManInDate()));
            CheckInDaysVo checkInDaysVo = omcReturnFeeConfigService.queryCheckInDaysVo(checkInDaysDto);

            prepaidCycleNum = prepaidCycleNum.add(checkInDaysVo.getPayPercent());

        }
        return prepaidCycleNum;
    }

    //状态码为1时，人工减免页面做回显，为0时，人工减免页面重新录入
    private int changeStatusByOldmanId(Long oldmanId,int status) {
        OmcOldmanExpenseItem updateItem = new OmcOldmanExpenseItem();
        updateItem.setOldmanId(oldmanId);
        List<OmcOldmanExpenseItem> oldmanExpenseItemList = select(updateItem);
        int count = 0;
        if(oldmanExpenseItemList != null && oldmanExpenseItemList.size() >0){
            for(OmcOldmanExpenseItem item : oldmanExpenseItemList){
                item.setStatus(status);
                int a = omcOldmanExpenseItemMapper.updateByPrimaryKey(item);
                count += a;
            }
        }
        return count;
    }

    //床位状态校验
    public void checkBedStatus(Long bedId,Long oldmanId){
        //校验床位状态
        Bed bed = bedService.selectById(bedId.intValue());
        if(bed.getStatus() != 0){
            throw new OmcBizException(ErrorCodeEnum.OMC10034006);
        }
    }

    public void checkBillStatus(Long oldmanId){
        /*
        * 2019-11-18
        * 修改缴费单校验的代码
        * 1.解决二次入院的问题
        * 2.防止随意修改入院流程选择的床位id
        * */
        OmcOldManBill billQuery = new OmcOldManBill();
        billQuery.setOldManId(oldmanId);
        billQuery.setBillType(1);
        List<OmcOldManBill> billList = omcOldManBillService.select(billQuery);

        //当有未支付的入院缴费单 或者 没有入院缴费单时 将其置为1
        int flag = 0;
        if(billList.size() == 0){
            flag = 1;
        } else {
            for (OmcOldManBill bill : billList) {
                if (bill.getIsPay().equals(0)) {
                    flag = 1;
                }
            }
        }

        Oldman oldman = new Oldman();
        oldman.setOldmanId(oldmanId.intValue());
        oldman = oldmanService.selectByOld(oldman);
        if(oldman != null && oldman.getStatus().equals(Constant.YIPINGGU) || oldman != null && oldman.getStatus().equals(Constant.DAIJIAOFEI)){
            flag = 1;
        }
        if (flag == 0) {
            throw new OmcBizException(ErrorCodeEnum.OMC10037025);
        }

//        Example example = new Example(OmcOldManBill.class);
//        Example.Criteria criteria = example.createCriteria();
//        criteria.andEqualTo("oldManId",oldmanId);
//
//        //缴费单类型 1-入院缴费单
//        criteria.andEqualTo("billType",1);
//
//        //支付状态 1-支付
//        criteria.andEqualTo("isPay",1);
//        if(omcOldManBillService.selectCountByExample(example) > 0){
//            throw new OmcBizException(ErrorCodeEnum.OMC10037025);
//        }
    }

    //校验机构缴费模式码是否配置完整
    public void checkExpenseTypeModelCodeComplete(LoginAuthDto loginAuthDto){

        //查询该机构消费类别
        OmcExpenseType typeQuery = new OmcExpenseType();
        typeQuery.setGroupId(loginAuthDto.getGroupId());
        List<OmcExpenseType> expenseTypeList = omcExpenseTypeService.select(typeQuery);

        //查询该机构费用类别配置
        OmcExpenseTypeModelCode modelCodeQuery = new OmcExpenseTypeModelCode();
        modelCodeQuery.setGroupId(loginAuthDto.getGroupId());
        List<OmcExpenseTypeModelCode> expenseTypeModelCodeList = omcExpenseTypeModelCodeService.select(modelCodeQuery);

        //校验是否配置完整
        int count = 0;
        for(OmcExpenseType type : expenseTypeList){
            for(OmcExpenseTypeModelCode modelCode : expenseTypeModelCodeList){
                if(type.getId().equals(modelCode.getExpenseTypeId())){
                    count++;
                }
            }
        }
        if(expenseTypeList.size() != count){
            throw new OmcBizException(ErrorCodeEnum.OMC10037037);
        }
    }

    public void checkPaymentCycleConfigExsit(LoginAuthDto loginAuthDto){
        OmcPaymentCycle paymentCycle = new OmcPaymentCycle();
        paymentCycle.setGroupId(loginAuthDto.getGroupId());
        paymentCycle = omcPaymentCycleService.selectOne(paymentCycle);
        if(paymentCycle == null || paymentCycle.getPaymentRecordGenerateConfig().equals("")){
            throw new OmcBizException(ErrorCodeEnum.OMC10037039);
        }

    }

    public List<ExpenseItemVo> moveQueryOldmanExpenseItem(Long oldmanId, LoginAuthDto loginAuthDto) {

        //定义已选择的消费项目Id集合
        List<Long> selectedItemIdList = new LinkedList<>();

        //查询老人已选择的消费项目
        OmcOldmanExpenseItem oldmanExpenseItemQuery = new OmcOldmanExpenseItem();
        oldmanExpenseItemQuery.setOldmanId(oldmanId);
        List<OmcOldmanExpenseItem> oldmanExpenseItemList = select(oldmanExpenseItemQuery);
        if(oldmanExpenseItemList == null || oldmanExpenseItemList.size() <1){
            return null;
        }else{
            //将消费项目id放入List
            for(OmcOldmanExpenseItem item : oldmanExpenseItemList){
                selectedItemIdList.add(item.getExpenseItemId());
            }
            //按消费项目Id查询老人选择的消费项目的详细信息（包括减免比例）
            List<ExpenseItemVo> expenseItemVoList = omcOldmanExpenseItemMapper.queryOldmanExpenseItem(oldmanId,selectedItemIdList);

            /*
             * 未配置减免比例时，无法使用queryOldmanExpenseItem()方法查到消费项目
             * 如果未配置人员减免比例，按不减免计算
             * 将未查到的消费项目id通过queryOldmanExpenseItemWithoutSubPersent()方法查询，并将两个结果集合并返回
             * */
            if(expenseItemVoList.size() < oldmanExpenseItemList.size()){

                //移除已经查询到的消费项目id
                int maxSize = selectedItemIdList.size();
                for (int i = maxSize-1; i >=0; i--) {
                    int size = expenseItemVoList.size();
                    while (size > 0) {
                        if (expenseItemVoList.get(size-1).getId().equals(selectedItemIdList.get(i))) {
                            selectedItemIdList.remove(i);
                            break;
                        }
                        size--;
                    }
                }
                //查询剩余消费项目
                List<ExpenseItemVo> surplusVoList = omcOldmanExpenseItemMapper.queryOldmanExpenseItemWithoutSubPersent(selectedItemIdList);
                for(ExpenseItemVo vo : surplusVoList){
                    vo.setPrecent(0);
                    expenseItemVoList.add(vo);
                }
                //判断老人是否选择了消费项目
                if(expenseItemVoList.size() != oldmanExpenseItemList.size()){
                    throw new OmcBizException(ErrorCodeEnum.OMC10037015);
                }
            }

            //先查询原来老人购买时的价格
            OmcOldmanPaidExpenseItem originalItemQuery = new OmcOldmanPaidExpenseItem();
            originalItemQuery.setOldmanId(oldmanId);
            List<OmcOldmanPaidExpenseItem> originalItemList = omcOldmanPaidExpenseItemService.select(originalItemQuery);

            //如果选择的项目有重复的，按原来选择该项目时的价格计算
            if(originalItemList.size() > 0){
                for(ExpenseItemVo vo : expenseItemVoList){
                    for(OmcOldmanPaidExpenseItem item : originalItemList){
                        if(vo.getId().equals(item.getExpenseItemId())){
                            vo.setChargeStandard(item.getItemFee());
                        }
                    }
                }
            }

            //计算减免金额
            for(ExpenseItemVo vo : expenseItemVoList){

                for(OmcOldmanExpenseItem item : oldmanExpenseItemList){
                    if(vo.getId().equals(item.getExpenseItemId())){

                        //获取非固定金额（前端保存的数据）
                        if(vo.getIsFixedPrice() == 0){
                            if(item.getChargeStandard() == null){
                                throw new OmcBizException(ErrorCodeEnum.OMC10037041);
                            }else{
                                BigDecimal fixedChargeStandard = item.getChargeStandard();
                                BigDecimal fixedUserTypeRateRefief = fixedChargeStandard.multiply(new BigDecimal (vo.getPrecent())).divide(new BigDecimal(100));
                                vo.setChargeStandard(item.getChargeStandard());
                                vo.setUserTypeRateRefief(fixedUserTypeRateRefief);
                            }
                            //获取固定金额
                        }else{
                            BigDecimal unFixedChargeStandard = vo.getChargeStandard();
                            BigDecimal unFixedUserTypeRateRefief = unFixedChargeStandard.multiply(new BigDecimal (vo.getPrecent())).divide(new BigDecimal(100));
                            vo.setUserTypeRateRefief(unFixedUserTypeRateRefief);
                        }
                        //放入购买件数
                        vo.setAmount(item.getAmount());
                        vo.setStatus(item.getStatus());
                    }
                }
            }
            return expenseItemVoList;
        }
    }

}
